package cn.maihe.elg.operation.centers.epoint.handler.service;

import cn.maihe.elg.operation.centers.epoint.annotation.Decryption;
import cn.maihe.elg.operation.centers.epoint.config.EpointCenterInfosConfig;
import cn.maihe.elg.operation.centers.epoint.dto.EpointBaseRespDTO;
import cn.maihe.elg.operation.centers.epoint.dto.handler.MeiShanProjectInfoDecryptionVo;
import cn.maihe.elg.operation.centers.epoint.dto.handler.MeiShanRestoreNotifyReq;
import cn.maihe.elg.operation.centers.epoint.enums.EpointRespCodeEnum;
import cn.maihe.elg.operation.centers.epoint.exception.EpointException;
import cn.maihe.elg.operation.centers.epoint.handler.EpointCenterTradeService;
import cn.maihe.elg.operation.centers.supports.CenterTradeContext;
import cn.maihe.elg.operation.centers.supports.annotation.CenterTradeService;
import cn.maihe.elg.operation.exception.CenterException;
import cn.maihe.elg.operation.model.enums.AcceptOrderStatus;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.CenterProviderEnum;
import cn.maihe.elg.operation.model.enums.TradeType;
import cn.maihe.elg.operation.repository.entity.AcceptOrderInfoDO;
import cn.maihe.elg.operation.repository.entity.InvoiceInfoDO;
import cn.maihe.elg.operation.repository.entity.ProjectInfoDO;
import cn.maihe.elg.operation.service.business.ProjectInfoService;
import cn.maihe.elg.operation.service.invoice.InvoiceInfoService;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.ApplyOrderInfoService;
import cn.maihe.elg.operation.utils.DateUtil;
import cn.maihe.elg.operation.utils.SM4Util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.CompletableFuture;

/**
 * @Description 还原保函
 * @Author SSX
 * @Date 2025/05/26
 */
@CenterTradeService(
        provider = CenterProviderEnum.EPOINT,
        centerNo = CenterNoEnum.MEISHAN,
        tradeType = TradeType.baohanrestore,
        reqClass = MeiShanRestoreNotifyReq.class,
        respClass = EpointBaseRespDTO.class
)
@Slf4j
public class MeiShanBaohanRestoreService extends EpointCenterTradeService<MeiShanRestoreNotifyReq, EpointBaseRespDTO> {
    public MeiShanBaohanRestoreService(EpointCenterInfosConfig centerInfosConfig) {
        super(centerInfosConfig);
    }

    @Resource(name = "guaranteeRestoreHandleExecutor")
    private ThreadPoolTaskExecutor executor;

    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;
    @Resource
    private ProjectInfoService projectInfoService;
    @Resource
    private ApplyOrderInfoService applyOrderInfoService;
    @Resource
    private InvoiceInfoService invoiceInfoService;

    @Override
    public EpointBaseRespDTO processService(CenterTradeContext<MeiShanRestoreNotifyReq, EpointBaseRespDTO> context) {
        MeiShanRestoreNotifyReq req = context.getReq();
        long centerId = context.getCenterId();
        long orgId = context.getOrgId();
        AcceptOrderInfoDO acceptOrderInfo = acceptOrderInfoService.getByCenterOrderId(centerId,orgId,req.getApplyno());

        if (acceptOrderInfo.getStatus() != AcceptOrderStatus.HAS_OUT_GUARANTEE.getStatus()) {
            return EpointBaseRespDTO.error("未出函，不能还原保函");
        }

        CompletableFuture.runAsync(() -> {
            try {
                ProjectInfoDO projectInfoDO = projectInfoService.selectById(acceptOrderInfo.getProjectId());
                if(projectInfoDO.getProjectEncryptionFlag() == 1){
                    MeiShanProjectInfoDecryptionVo projectInfoEncryptionVo = buildProjectInfoEncryption(projectInfoDO);
                    log.info("projectInfoEncryptionVo:{}", JSON.toJSONString(projectInfoEncryptionVo));
                    MeiShanProjectInfoDecryptionVo projectInfoDecryptionVo = decryptFiled(req, projectInfoEncryptionVo);
                    log.info("中心交易单号:{},受理订单号:{},projectInfoDecryptionVo.getBzjenddate:{},req.getBzjenddate:{}",req.getApplyno(), acceptOrderInfo.getAcceptOrderNo(),projectInfoDecryptionVo.getBzjenddate(),req.getBzjenddate());
                    log.info("projectInfoDecryptionVo:{}", JSON.toJSONString(projectInfoDecryptionVo));
                    ProjectInfoDO projectInfoDecryptionDO = buildProjectInfoDecryption(req, projectInfoDO, projectInfoDecryptionVo);
                    log.info("projectInfoDecryptionDO:{}", JSON.toJSONString(projectInfoDecryptionDO));
                    // 更新投标项目
                    projectInfoService.updateById(projectInfoDecryptionDO);

                    // 更新受理订单
                    AcceptOrderInfoDO acceptOrderInfoDO = buildAcceptOrderInfo(acceptOrderInfo.getId(),projectInfoDecryptionDO);
                    acceptOrderInfoService.updateById(acceptOrderInfoDO);
                }

                // 保函还原
                InvoiceInfoDO invoiceInfoDO = invoiceInfoService.selectById(acceptOrderInfo.getInvoiceId());
                AcceptOrderInfoDO acceptOrderInfoDO = acceptOrderInfoService.selectById(acceptOrderInfo.getId());
                applyOrderInfoService.applyGuarantee(acceptOrderInfoDO, invoiceInfoDO, null,true);
            } catch (Exception e) {
                log.error("中心交易单号:{},保函还原失败:{}",req.getApplyno(), e.getMessage(), e);
            }
        },executor);

        return EpointBaseRespDTO.success("保函还原处理中");
    }

    /**
     * 敏感字段解密
     *
     * @return
     */
    protected MeiShanProjectInfoDecryptionVo decryptFiled(MeiShanRestoreNotifyReq req, MeiShanProjectInfoDecryptionVo projectInfoEncryptionVo) {
        try {
            Field[] fields = projectInfoEncryptionVo.getClass().getDeclaredFields();
            Arrays.stream(fields).filter(f -> f.getAnnotation(Decryption.class) != null)
                    .forEach(f -> {
                        f.setAccessible(true);
                        try {
                            String encryptValue = (String) f.get(projectInfoEncryptionVo);
                            if (StringUtils.isNotBlank(encryptValue)) {
                                String decryptValue = this.decrypt4Epoint(req.getKey(), encryptValue);
                                f.set(projectInfoEncryptionVo, decryptValue);
                            }
                        } catch (Exception e) {
                            throw new RuntimeException("[" + f.getName() + "]字段解密异常:" + e.getMessage(), e);
                        }
                        f.setAccessible(false);
                    });
        } catch (Exception e) {
            throw EpointException.of(EpointRespCodeEnum.FAILURE, e.getMessage(), e);
        }
        return projectInfoEncryptionVo;
    }

    public String decrypt4Epoint(String key, String encryptedData) {
        Assert.hasText(encryptedData, () -> "待解密数据不能为空");
        byte[] enByte = Base64.decodeBase64(encryptedData);
        try {
            return new String(SM4Util.decrypt_ECB_Padding(Base64.decodeBase64(key), enByte), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw CenterException.exception("解密失败",e);
        }

    }

    private MeiShanProjectInfoDecryptionVo buildProjectInfoEncryption(ProjectInfoDO projectInfoDO) {
        JSONObject ciphertext = JSON.parseObject(projectInfoDO.getCiphertext());
        return JSON.parseObject(ciphertext.getString("meiShanProjectInfoDecryptionVo"), MeiShanProjectInfoDecryptionVo.class);
    }

    private ProjectInfoDO buildProjectInfoDecryption(MeiShanRestoreNotifyReq req, ProjectInfoDO projectInfoDO, MeiShanProjectInfoDecryptionVo projectInfoDecryptionVo) {
        return ProjectInfoDO.builder()
                .id(projectInfoDO.getId())
                .sectionCode(projectInfoDecryptionVo.getSectionCode())
                .sectionName(projectInfoDecryptionVo.getSectionName())
                .tenderer(projectInfoDecryptionVo.getTenderer())
                .tendererCreditCode(projectInfoDecryptionVo.getTendererCreditCode())
                .tendererContact(projectInfoDecryptionVo.getTendererContact())
                .tendererContactTel(projectInfoDecryptionVo.getTendererContactTel())
                .tendererAddress(projectInfoDecryptionVo.getTendererAddress())
                .bidOpenTime(DateUtil.parseDate(req.getKaibiaotime(), "yyyy-MM-dd HH:mm:ss"))
                .bidIndate(DateUtil.parseDate(req.getBzjenddate(), "yyyy-MM-dd HH:mm:ss"))
                .projectEncryptionFlag(2)
                .gmtModified(new Date())
                .build();
    }

    private AcceptOrderInfoDO buildAcceptOrderInfo(Long id ,ProjectInfoDO projectInfoDO) {
        return AcceptOrderInfoDO.builder()
                .id(id)
                .sectionName(projectInfoDO.getSectionName())
                .gmtModified(new Date())
                .build();
    }

}
